package tr.helper;

import java.lang.ref.WeakReference;
import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 　@description: 单例工厂
 * 　@author secret
 * 　@date 2021/1/5 19:43
 */
public class SingletonFactory {

    private static Map<Class, Object> instances = new ConcurrentHashMap<Class, Object>();
    private static Map<Class, WeakReference<Object>> weakReferenceInstances = new ConcurrentHashMap<Class, WeakReference<Object>>();

    /**
     * 创建可不被回收的单例模式,当没有对象引用，单例对象将被gc掉
     *
     * @param className
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    @SuppressWarnings("unchecked")
    public static <E> E getInstance(Class<E> className) {
        Object instace = instances.get(className);
        if (instace == null) {
            synchronized (SingletonFactory.class) {
                instace = instances.get(className);
                if (instace == null) {
                    try {
                        instace = className.newInstance();
                    } catch (InstantiationException e) {
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                    instances.put(className, instace);
                }
            }
        }
        return (E) instace;
    }

    /**
     * 创建可回收的单例模式,当没有对象引用，单例对象将被gc掉
     *
     * @param className
     * @return
     * @throws InstantiationException
     * @throws IllegalAccessException
     */
    @SuppressWarnings("unchecked")
    public static <E> E getWeakInstance(Class<E> className, Object[] parameters) {
        WeakReference<Object> reference = weakReferenceInstances.get(className);
        Object instace = reference == null ? null : reference.get();
        if (instace == null) {
            synchronized (SingletonFactory.class) {
                reference = weakReferenceInstances.get(className);
                instace = reference == null ? null : reference.get();
                if (instace == null) {
                    try {
                        instace = className.getDeclaredConstructor().newInstance(parameters);
                    } catch (InstantiationException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (IllegalAccessException e) {
                        // TODO Auto-generated catch block
                        e.printStackTrace();
                    } catch (NoSuchMethodException e) {
                        e.printStackTrace();
                    } catch (InvocationTargetException e) {
                        e.printStackTrace();
                    }
                    weakReferenceInstances.put(className, new WeakReference<Object>(instace));
                }
            }
        }
        return (E) instace;
    }

}
